package parser;

import antlr.RecognitionException;
import java.util.*;

abstract class Type {
    abstract void write(ByteStream out) throws RecognitionException;
    abstract void delete(ByteStream out) throws RecognitionException;
    abstract void writeLHS(ByteStream out) throws RecognitionException;
    public boolean is_deref() { return false; }
}  

class FastLocal extends Type {
    
    FastLocal(int index) {
        this.index = index;   
    }
    
    void write(ByteStream out) throws RecognitionException {
        out.write(Opcodes.LOAD_FRAME);
        out.write(index);
    }

    void delete(ByteStream out) throws RecognitionException {
        out.write(Opcodes.DELETE);
        out.write(index);
    }
    
    void writeLHS(ByteStream out) throws RecognitionException {
        out.write(Opcodes.STORE_FRAME);
        out.write(index);
    }

    int index;
}

class DeRef extends Type {
    
    DeRef(int index, int link) {
        this.index = index;
        this.link = link;
    }
    
    void write(ByteStream out) throws RecognitionException {
        out.write(Opcodes.LOAD_DEREF);
        out.write(link);
        out.write(index);
    }

    void delete(ByteStream out) throws RecognitionException {
        throw new RecognitionException("Cannot delete non-local variables");
    }
    
    void writeLHS(ByteStream out) throws RecognitionException {
        out.write(Opcodes.STORE_DEREF);
        out.write(link);
        out.write(index);
    }

    public boolean is_deref() { return true; } 

    int index;
    int link;
}

class GlobalVar extends Type {
       
    GlobalVar(int name) {
        this.name = name;   
    }
    
    void write(ByteStream out) throws RecognitionException {
        out.write(Opcodes.LOAD_GLOBAL);
        out.writeShort(name);
    }

    void delete(ByteStream out) throws RecognitionException {
        out.write(Opcodes.DELETE_GLOBAL);
        out.writeShort(name);
    }
    
    void writeLHS(ByteStream out) throws RecognitionException {
        out.write(Opcodes.STORE_GLOBAL);
        out.writeShort(name);
    }

    int name;
    
}

class NamedLocal extends Type {
       
    NamedLocal(int name) {
        this.name = name;   
    }
    
    void write(ByteStream out) throws RecognitionException {
        out.write(Opcodes.LOAD_LOCAL);
        out.writeShort(name);
    }

    void delete(ByteStream out) throws RecognitionException {
        out.write(Opcodes.DELETE_LOCAL);
        out.writeShort(name);
    }
    
    void writeLHS(ByteStream out) throws RecognitionException {
        out.write(Opcodes.STORE_LOCAL);
        out.writeShort(name);
    }

    int name;
    
}

class GeneralLocal extends Type {
       
    GeneralLocal(int name) {
        this.name = name;   
    }
    
    void write(ByteStream out) throws RecognitionException {
        out.write(Opcodes.LOAD);
        out.writeShort(name);
    }

    void delete(ByteStream out) throws RecognitionException {
        throw new RecognitionException("Cannot delete non-local variables");
    }
    
    void writeLHS(ByteStream out) throws RecognitionException {
        throw new Error("Cannot have a store to a variable of unknown location");
//        out.write(Opcodes.STORE);
//        out.writeShort(name);
    }

    int name;
    
}

